#pragma once
#ifndef __MY_HELPPER__
#define __MY_HELPPER__

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <random>
#include <iomanip>
#include <atomic>
#include <fstream>
#include <filesystem>
#include <algorithm>
#include "sqlite3.h"
#include "logger.hpp"

namespace NS_Helper
{
    using SQLCallback = int(void *, int, char **, char **);
    class SQLite3Helper
    {
    public:
        SQLite3Helper(const std::string &file_path_name) : _file_path_name(file_path_name), _handler(nullptr)
        {
        }

        bool open(int security_level = SQLITE_OPEN_FULLMUTEX)
        {
            int ret = sqlite3_open_v2(_file_path_name.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | security_level, nullptr);
            if (ret != SQLITE_OK)
            {
                DLOG("打开或创建文件 %s 失败\n, 原因：%s\n", _file_path_name.c_str(), sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }

        bool insert(const std::string &sql)
        {
            return execute(sql);
        }

        bool erase(const std::string &sql)
        {
            return execute(sql);
        }

        bool update(const std::string sql)
        {
            return execute(sql);
        }

        template <class T>
        bool select(const std::string sql, SQLCallback cb, T &container)
        {
            return execute(sql, cb, &container);
        }

        ~SQLite3Helper()
        {
            sqlite3_close_v2(_handler);
        }

    private:
        bool execute(const std::string sql, SQLCallback cb = nullptr, void *arg = nullptr, char **err = nullptr)
        {
            int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, err);
            if (ret != SQLITE_OK)
            {
                DLOG("SQL语句： %s 失败\n, 原因：%s\n", sql.c_str(), sqlite3_errmsg(_handler));
                return false;
            }

            return true;
        }

    private:
        std::string _file_path_name;
        sqlite3 *_handler;
    };

    class String
    {
    public:
        static void split(const std::string &str, const std::string &seq, std::vector<std::string> &res)
        {
            size_t pos = 0, idx = 0;
            while (idx < str.size())
            {
                pos = str.find(seq, idx);

                if (pos == std::string::npos)
                {
                    res.push_back(str.substr(idx, pos - idx));
                    return;
                }

                if (pos == idx)
                {
                    idx = pos + seq.size();
                    continue;
                }

                res.push_back(str.substr(idx, pos - idx));
                idx = pos + seq.size();
            }

            return;
        }
    };

    class Uuid
    {
    public:
        static std::string uuid()
        {
            std::string ret;
            int seed = std::random_device()();
            std::mt19937 generator(seed);
            std::uniform_int_distribution<size_t> distribution(0, 255);
            std::stringstream ss;

            for (int i = 0; i < 8; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << (distribution(generator));
                if (i == 3 || i == 7 || i == 5)
                    ss << "-";
            }

            static std::atomic<size_t> seq(0);
            for (int i = 0; i < 8; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << ((seq.load() >> (((7 - i) * 8))) & 0xff);
                if (i == 1)
                    ss << "-";
            }
            ++seq;

            ss >> ret;
            return ret;
        }
    };

    class FileHelper
    {
    public:
        FileHelper(std::string filename)
            : _filename(filename)
        {
        }

        // 如果你用的是 C++17 及以上版本，可以使用 std::filesystem，这是一种更现代、更优雅的方式
        bool exist()
        {
            return std::filesystem::exists(_filename);
        }

        // C++ 规定 seekg() 需要传入 std::ios::beg 作为参考点
        //
        int size()
        {
            // 使用 std::ios::ate这个标志 (ate = "at end") 让 ifstream 在打开文件时直接跳到末尾，
            // 然后我们可以直接调用 tellg() 获取大小，无需手动调用 seekg()，这样代码更简洁高效。
            std::ifstream in(_filename, std::ios::binary | std::ios::ate);
            if (!in.is_open())
            {
                ELOG("无法打开文件 %s", _filename.c_str());
                return -1;
            }

            std::streamsize length = in.tellg();
            if (length < 0)
            {
                ELOG("无法获取文件大小 %s", _filename.c_str());
                in.close();
                return -1;
            }

            in.close();
            return static_cast<size_t>(length);
        }

        int read(std::vector<char> &buffer)
        {
            std::ifstream in(_filename, std::ios::binary);
            if (!in.is_open())
            {
                ELOG("无法打开文件 %s", _filename.c_str());
                return -1;
            }

            // 获取文件大小
            in.seekg(0, std::ios::end);
            size_t file_size = in.tellg();
            in.seekg(0, std::ios::beg);

            // 调用已有的 read() 读取整个文件
            int ret = read(buffer, 0, file_size);
            in.close();

            return ret;
        }

        int read(std::string &buffer)
        {
            std::ifstream in(_filename, std::ios::binary);
            if (!in.is_open())
            {
                ELOG("无法打开文件 %s", _filename.c_str());
                return -1;
            }

            // 获取文件大小
            in.seekg(0, std::ios::end);
            size_t file_size = in.tellg();
            in.seekg(0, std::ios::beg);

            // 调用已有的 read() 读取整个文件
            int ret = read(buffer, 0, file_size);
            in.close();

            return ret;
        }

        int read(std::vector<char> &buffer, size_t pos, size_t len)
        {
            std::ifstream in(_filename, std::ios::binary);
            if (!in.is_open())
            {
                ELOG("无法打开文件 %s", _filename.c_str());
                return -1;
            }

            // 先尝试定位到 pos 位置
            if (!in.seekg(pos))
            {
                ELOG("文件 %s 的偏移 %zu 无效", _filename.c_str(), pos);
                in.close();
                return -1;
            }

            // 预分配空间
            buffer.resize(len);

            // 读取文件内容
            in.read(buffer.data(), len);
            size_t read_len = in.gcount(); // 获取实际读取的字节数

            // 处理可能的读取不足情况
            if (read_len < len)
            {
                ELOG("文件 %s 读取数据不足: 期望 %zu 字节，实际 %zu 字节", _filename.c_str(), len, read_len);
                buffer.resize(read_len); // 调整 vector 大小
            }
            in.close();

            return static_cast<int>(read_len);
        }

        int read(std::string &buffer, size_t pos, size_t len)
        {
            std::ifstream in(_filename, std::ios::binary);
            if (!in.is_open())
            {
                ELOG("无法打开文件 %s", _filename.c_str());
                return -1;
            }

            // 先尝试定位到 pos 位置
            if (!in.seekg(pos))
            {
                ELOG("文件 %s 的偏移 %zu 无效", _filename.c_str(), pos);
                in.close();
                return -1;
            }

            // 预分配空间
            buffer.resize(len);

            // 读取文件内容
            in.read(buffer.data(), len);
            size_t read_len = in.gcount(); // 获取实际读取的字节数

            // 处理可能的读取不足情况
            if (read_len < len)
            {
                ELOG("文件 %s 读取数据不足: 期望 %zu 字节，实际 %zu 字节", _filename.c_str(), len, read_len);
                buffer.resize(read_len); // 调整 vector 大小
            }
            in.close();

            return static_cast<int>(read_len);
        }

        int write(const std::string &buffer, size_t pos, size_t len)
        {
            std::ofstream out(_filename, std::ios::binary | std::ios::in | std::ios::out);
            if (!out.is_open())
            {
                ELOG("无法打开文件 %s 进行写入", _filename.c_str());
                return -1;
            }

            // 先尝试定位到 pos 位置
            if (!out.seekp(pos))
            {
                ELOG("文件 %s 的偏移 %zu 无效", _filename.c_str(), pos);
                out.close();
                return -1;
            }

            // 写入数据
            out.write(buffer.data(), len);
            if (!out)
            {
                ELOG("文件 %s 写入失败", _filename.c_str());
                out.close();
                return -1;
            }
            out.close();

            return len;
        }

        // **重载函数：写入整个 buffer**
        int write(const std::string &buffer)
        {
            std::ofstream out(_filename, std::ios::binary | std::ios::trunc);
            if (!out.is_open())
            {
                ELOG("无法打开文件 %s 进行写入", _filename.c_str());
                return -1;
            }

            // 直接写入整个字符串
            out.write(buffer.data(), buffer.size());
            if (!out)
            {
                ELOG("文件 %s 写入失败", _filename.c_str());
                out.close();
                return -1;
            }
            out.close();

            return buffer.size();
        }

        static bool renameFile(const std::string &old_name, const std::string &new_name)
        {
            if (std::rename(old_name.c_str(), new_name.c_str()) != 0)
            {
                ELOG("文件重命名失败: %s -> %s", old_name.c_str(), new_name.c_str());
                return false;
            }
            return true;
        }

        static std::string getParentDirectory(const std::string &path)
        {
            try
            {
                std::filesystem::path p(path);
                return p.parent_path().string(); // 获取父目录路径
            }
            catch (const std::exception &e)
            {
                ELOG("获取父目录失败: %s", e.what());
                return "";
            }
        }

        static bool createFile(const std::string &filename)
        {
            if (FileHelper(filename).exist())
                return true;
            std::ofstream file(filename, std::ios::binary);
            if (!file)
            {
                ELOG("无法创建文件: %s", filename.c_str());
                return false;
            }
            file.close(); // 关闭文件
            return true;
        }

        static bool deleteFile(const std::string &filename)
        {
            if (std::remove(filename.c_str()) != 0)
            {
                ELOG("无法删除文件: %s", filename.c_str());
                return false;
            }
            return true;
        }

        static bool createDirectory(const std::string &dir)
        {
            try
            {
                // 创建多级目录
                if (std::filesystem::create_directories(dir))
                {
                    return true;
                }
                else
                {
                    // ELOG("目录已存在或无法创建: %s", dir.c_str());
                    return false;
                }
            }
            catch (const std::exception &e)
            {
                ELOG("创建目录失败: %s", e.what());
                return false;
            }
        }

        static bool deleteDirectory(const std::string &dir)
        {
            try
            {
                // 递归地删除层级目录及其目录中的所有文件
                if (std::filesystem::remove_all(dir) > 0)
                {
                    return true;
                }
                else
                {
                    ELOG("删除目录失败或目录不为空: %s", dir.c_str());
                    return false;
                }
            }
            catch (const std::exception &e)
            {
                ELOG("删除目录失败: %s", e.what());
                return false;
            }
        }

        ~FileHelper() {}

    private:
        std::string _filename;
    };

    class DecimalConversion
    {
    public:
        static bool decimalToBase62(int num, std::string &res)
        {
            std::string tmp;
            while (num)
            {
                int mod = num % 62;
                char ch = 0;
                if (mod >= 0 && mod <= 9)
                    ch = mod + '0';
                else if (mod >= 10 && mod <= 35)
                {
                    ch = mod + 'A' - 10;
                }
                else
                    ch = mod + 'a' - 36;

                tmp.push_back(ch);
                num /= 62;
            }

            if (tmp.size() > 5)
            {
                ELOG("消息长度 %d 大于阈值", num);
                return false;
            }
            std::reverse(tmp.begin(), tmp.end());
            res = std::string(5 - (int)tmp.size(), '0') + tmp;
            return true;
        }

        static bool base62ToDecimal(const std::string &num, size_t &res)
        {
            for (auto ch : num)
            {
                if (!((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
                {
                    ELOG("该字符串不是62进制数字，%s", num.c_str());
                    return false;
                }
            }

            res = 0;
            for (int i = num.size() - 1, power = 0; i >= 0; i--)
            {
                int low_position = 0;
                if (num[i] >= '0' && num[i] <= '9')
                    low_position = num[i] - '0';
                else if (num[i] >= 'A' && num[i] <= 'Z')
                    low_position = num[i] - 'A' + 10;
                else
                    low_position = num[i] - 'a' + 36;

                res += (low_position * pow(62, power++));
            }

            return true;
        }
    };

}

#endif